package message.visitor;

import java.io.IOException;

import message.Message;
import message.MessageParser;
import message.types.data.AddDataRequest;
import message.types.data.GetAllDatasAnswer;
import message.types.data.GetLastDataAnswer;
import message.types.message.RejectedRequest;
import message.types.none.GetAllDatasRequest;
import message.types.none.GetLastDataRequest;
import message.types.none.NewDataNotification;
import message.types.stalker.LogOffNotification;
import message.types.stalker.LoginSuccessAnswer;
import message.types.stalker.RegisterRequest;
import message.types.stalkerstring.GetRoomFromNameAnswer;
import message.types.stalkerstring.GetUserFromNameAnswer;
import message.types.string.CreatePrivatePersistentRoomRequest;
import message.types.string.CreateRoomRequest;
import message.types.string.GetRoomFromNameRequest;
import message.types.string.GetUserFromNameRequest;
import message.types.unique.EmptyMessage;
import message.types.unique.RoomInvitation;
import network.e2e.FrameWriter;
import stalker.user.User;

/**
 * Visitor that handles user messages
 */

public class UserMessageVisitor extends MessageVisitor<Void> {
  
  private User user_;
  private FrameWriter cout_;
  
  /**
   * Constructs a user message visitor for a user
   * @requires user not null
   * @param user spawner of this visitor
   * @param cout writer to communicate with the client side
   */
  public UserMessageVisitor(User user, FrameWriter cout) {
    assert user != null && cout != null;
    cout_ = cout;
    user_ = user;
    assert (user_ != null);
  }
  
  /**
   * Relays a message to the client side
   * @requires message not null
   * @param message message to be relayed
   */
  private void relayOverNet(Message message) {
    assert message != null;
    try {
      System.out.println("Sending : " + message);
      MessageParser.send(message, cout_);
    } catch (IOException e) {
      System.out.println("Failed to transmit " + message);
    }
  }

  @Override
  public Void visit(AddDataRequest addDataReq) {
    assert addDataReq != null;
    relayMessage(addDataReq);
    return null;
  }

  @Override
  public Void visit(GetLastDataRequest getLastReq) {
    assert getLastReq != null;
    relayMessage(getLastReq);
    return null;
  }
  
  @Override
  public Void visit(RegisterRequest getRegisterReq) {
    assert getRegisterReq != null;
    relayMessage(getRegisterReq);
    return null;
  }

  @Override
  public Void visit(GetLastDataAnswer getLastAns) {
    assert getLastAns != null;
    relayOverNet(getLastAns);
    return null;
  }

  @Override
  public Void visit(EmptyMessage getEmptyMsg) {
    return null;
  }

  @Override
  public Void visit(LoginSuccessAnswer getLoginSuccessAns) {
    assert getLoginSuccessAns != null;
    relayOverNet(getLoginSuccessAns);
    return null;
  }
  
  @Override
  public Void visit(CreateRoomRequest createRoomReq) {
    assert createRoomReq != null;
    relayMessage(createRoomReq);
    return null;
  }
  
  @Override
  public Void visit(CreatePrivatePersistentRoomRequest createRoomReq) {
    assert (createRoomReq != null);
    relayMessage(createRoomReq);
    return null;
  }

  @Override
  public Void visit(RoomInvitation roomInvit) {
    assert roomInvit != null;
    relayOverNet(roomInvit);
    return null;
  }

  @Override
  public Void visit(GetAllDatasRequest getAllData) {
    assert getAllData != null;
    relayMessage(getAllData);
    return null;
  }

  @Override
  public Void visit(GetAllDatasAnswer getAllAns) {
    assert getAllAns != null;
    relayOverNet(getAllAns);
    return null;
  }

  @Override
  public Void visit(GetUserFromNameRequest getStalkerFromName) {
    assert getStalkerFromName != null;
    relayMessage(getStalkerFromName);
    return null;
  }

  @Override
  public Void visit(GetUserFromNameAnswer getStalkerFromName) {
    assert getStalkerFromName != null;
    relayOverNet(getStalkerFromName);
    return null;
  }
  
  @Override
  public Void visit(NewDataNotification new_data_notif) {
    assert new_data_notif != null;
    relayOverNet(new_data_notif);
    return null;
  }
  
  @Override
  public Void visit(LogOffNotification logOffNotif) {
    assert (logOffNotif != null);
    user_.deactivate();
    return null;
  }
  
  @Override
  public Void visit(GetRoomFromNameRequest get_stalker_from_name) {
    assert (get_stalker_from_name != null);
    relayMessage(get_stalker_from_name);
    return null;
  }
  
  @Override
  public Void visit(GetRoomFromNameAnswer get_stalker_from_name) {
    assert (get_stalker_from_name != null);
    relayOverNet(get_stalker_from_name);
    return null;
  }

  @Override
  public Void visit(RejectedRequest rejectedRequest) {
    
    assert rejectedRequest != null;
    
    if (rejectedRequest.getDestination().equals(user_)) {
      relayOverNet(rejectedRequest);
    } else {
      relayMessage(rejectedRequest);
    }
    
    return null;
  }
  
}
